$fn=60;

// fan itself
fanLen = 180;
fanDepth = 35;
fanRoundingRad = 10;

// outer printed rim around fan
rimLen = 20;
rimDepth = fanDepth + 5;
rimRoundingRad = 3;

// banana plug
bananaHeadLen = 21.1;
bananaHeadDia = 10.3;
bananaRodLen=20;
bananaRodDia=5;
bananaNutLen=4.1;
bananaNutDia=9.2;
bananaNutSidelen = bananaNutDia/2.0;
//@see https://www.redcrab-software.com/de/Rechner/Hexagon
bananaNutInsideDia = (sqrt(3) * bananaNutSidelen);

// cut out channel
cutoutGap=5;

// grid cut out on back
gridSideLen=30;
gridGap=2;
gridSize=30;


/////////////////////////////////////////////////////////////////////////
// Main
/////////////////////////////////////////////////////////////////////////

difference()
{
// outer enclosure:
makeEnclosure();
// banana plugs:
translate([rimLen+fanLen/2-bananaHeadDia,rimDepth+5,rimLen/2])
  color("red") makeBananaPlug();
translate([rimLen+fanLen/2+bananaHeadDia,rimDepth+5,rimLen/2])
  color("black") makeBananaPlug();
// cut out channel for banana plug
translate([rimLen+fanLen/2-bananaHeadDia,rimDepth-bananaHeadLen,rimLen/2])
  makeBananaCutOut();
translate([rimLen+fanLen/2+bananaHeadDia,rimDepth-bananaHeadLen,rimLen/2])
  makeBananaCutOut();
// cut out channel for cable
translate([fanLen/2+rimLen-bananaHeadDia-bananaNutInsideDia/2,rimDepth-bananaHeadLen-(bananaRodLen-cutoutGap),rimLen/2+bananaNutDia/2])
  makeCableCutOut();
// cut out grid on backside
translate([0.05,rimDepth-gridSideLen+1,0.05]) 
  makeGridCutOut();
// cut out label: - 12V +
makeLabels();
}

/////////////////////////////////////////////////////////////////////////
// Modules
/////////////////////////////////////////////////////////////////////////
module makeLabels()
{
  translate([fanLen/2+rimLen,rimDepth-2, 8])
  rotate([90,0,180]) linear_extrude(height=3) 
    text("-    12    +", size = 4, halign="center", font="Andale Mono");
}
/////////////////////////////////////////////////////////////////////////
module makeGridCutOut()
{
  intersection()
  {
    scale([0.999,0.999,0.999]) makeFan();
    translate([-(gridSize*(gridSideLen+gridGap)/2)+3,0,-3]) rotate([0,45,0])
      makeGrid(gridSideLen,gridSideLen,gridGap, gridSize) {cube(gridSideLen);};
  }
}
/////////////////////////////////////////////////////////////////////////
module makeGrid(objectLen, objectHeight, spacing, gridSize)
{
  for( a = [0 : gridSize-1])
  {
    translate([a*objectLen+a*spacing, 0, 0])
    for( a = [0 : gridSize-1])
    {
      translate([0, 0, a*objectHeight+a*spacing])
      children(0);
    }
  }
}
/////////////////////////////////////////////////////////////////////////
module makeCableCutOut()
{
  cube([fanLen/2+bananaHeadDia+bananaNutInsideDia/2,bananaRodLen-cutoutGap,rimLen],center=false);
}
/////////////////////////////////////////////////////////////////////////
module makeBananaCutOut()
{
translate([0,-((bananaRodLen-cutoutGap)/2),0])
union()
  {
  translate([0,0,rimLen/2])
    cube([bananaNutInsideDia,bananaRodLen-cutoutGap,rimLen],center=true);
  rotate([90,90,0]) 
    cylinder(d=bananaNutDia, h=bananaRodLen-cutoutGap, center=true, $fn=6);
  }
}
/////////////////////////////////////////////////////////////////////////
module makeBananaPlug()
{
  translate([0,-bananaRodLen/2-bananaHeadLen+0.1,0])
  rotate([-90,0,0])
  union()
  {
    // head
    translate([0,0,bananaHeadLen/2+bananaRodLen/2-0.1])
    cylinder(d=bananaHeadDia, h=bananaHeadLen, center=true);
    // rod
    cylinder(d=bananaRodDia, h=bananaRodLen, center=true);
    // nut
//    rotate([0,0,30])
//    translate([0,0,-bananaRodLen/2+bananaNutLen/2+1])
//    cylinder(d=bananaNutDia, h=bananaNutLen, center=true, $fn=6);
  }
}
/////////////////////////////////////////////////////////////////////////
module makeEnclosure()
{
  difference()
  {
    makeRim();
    makeFan();
  }
}
/////////////////////////////////////////////////////////////////////////
module makeRim()
{
translate([rimRoundingRad,rimDepth,rimRoundingRad])
rotate([90,0,0])
  minkowski()
  {
    cube([fanLen+2*rimLen-2*rimRoundingRad,fanLen+2*rimLen-2*rimRoundingRad,rimDepth-1]);
    cylinder(r=rimRoundingRad,h=1);
  }    
}
/////////////////////////////////////////////////////////////////////////
module makeFan()
{
translate([fanRoundingRad+rimLen,fanDepth,fanRoundingRad+rimLen])
rotate([90,0,0])
  minkowski()
  {
    cube([fanLen-2*fanRoundingRad,fanLen-2*fanRoundingRad,fanDepth]);
    cylinder(r=fanRoundingRad,h=1);
  }    
}
/////////////////////////////////////////////////////////////////////////
